package com.htdata.iiot.tools;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.TreeMap;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class UrlInspect {
	private static Integer num = 0;

	public static final String HELP = "help";
	public static final String EXCEL = "excel";
	public static final String FROM = "from";
	public static final String TO = "to";
	public static final String THREADS = "threads";

	public static final String METHOD = "method";
	public static final String APIKEY = "apiKey";
	public static final String URL = "url";
	public static final String PAYLOAD = "payload";

	public static ArrayList<TreeMap<String, String>> ReadExcel(String fileName) {
		ArrayList<TreeMap<String, String>> arrayList = new ArrayList<TreeMap<String, String>>();
		File file = null;
		Workbook workbook = null;
		Sheet sheet = null;

		InputStream inputStream = null;
		try {
			file = new File(fileName);
			inputStream = new FileInputStream(file.getAbsolutePath());
			workbook = WorkbookFactory.create(inputStream);
			int numberOfSheets = workbook.getNumberOfSheets();
			if (numberOfSheets < 1) {
				throw new Exception("`" + fileName + "` has no sheet!");
			}

			sheet = workbook.getSheetAt(0);

			int i = 0;
			int j = 0;
			Cell cell = null;
			String method = null;
			String apiKey = null;
			String url = null;
			String payload = null;
			// 首行为标题行，跳过
			for (i = sheet.getFirstRowNum() + 1; i <= sheet.getLastRowNum(); i++) {
				Row row = sheet.getRow(i);
				if (row == null) {
					break;
				}

				TreeMap<String, String> map = new TreeMap<String, String>();

				// 第一列为编号，从第二列开始
				j = row.getFirstCellNum() + 1;
				cell = row.getCell(j);
				if (cell != null) {
					method = cell.getStringCellValue();
					if (method != null) {
						map.put(UrlInspect.METHOD, method.toUpperCase().trim());
					}
				}

				j++;
				cell = row.getCell(j);
				if (cell != null) {
					apiKey = cell.getStringCellValue();
					if (apiKey != null) {
						map.put(UrlInspect.APIKEY, apiKey.trim());
					}
				}

				j++;
				cell = row.getCell(j);
				if (cell != null) {
					url = cell.getStringCellValue();
					if (url != null) {
						map.put(UrlInspect.URL, url.trim());
					}
				}

				j++;
				cell = row.getCell(j);
				if (cell != null) {
					payload = cell.getStringCellValue();
					if (payload != null) {
						map.put(UrlInspect.PAYLOAD, payload.trim());
					}
				}

				arrayList.add(map);
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
		} finally {
			try {
				if (workbook != null) {
					workbook.close();
				}

				if (inputStream != null) {
					inputStream.close();
				}
			} catch (Exception e) {
			}
		}

		if (arrayList.isEmpty()) {
			arrayList = null;
		}

		return arrayList;
	}

	public static void usage(Options options) {
		HelpFormatter helpFormatter = new HelpFormatter();
		helpFormatter.setOptionComparator(null);
		helpFormatter.setWidth(120);
		helpFormatter.printHelp("urlInspect -e <fileName> [-f <SeqNumFrom>] [-t <SeqNumTo>] [-T <threads>]", options);
	}

	public static void main(String[] args) throws ParseException, InterruptedException {
		String fileName = null;
		int from = -1;
		int to = -1;
		int threads = -1;
		int i = 0;

		Options optionsH = new Options();
		optionsH.addOption("h", UrlInspect.HELP, false, "show help information");

		Options options = new Options();
		options.addRequiredOption("e", UrlInspect.EXCEL, true, "filename of excel with ignored 1st line, columns: SeqNum, Method, ApiKey, Url, Payload");
		options.addOption("f", UrlInspect.FROM, true, "from SeqNum, 1 based, included");
		options.addOption("t", UrlInspect.TO, true,   "to   SeqNum: 1 based, included");
		options.addOption("T", UrlInspect.THREADS, true, "number of cocurrent threads");

		if(args.length == 0){
			usage(options);
			return;
		}
		
		
		CommandLine commandLine = null;
		CommandLineParser parser = null;
		parser = new DefaultParser();
		
		try {
			commandLine = parser.parse(optionsH, args);
			if (commandLine.hasOption(UrlInspect.HELP)) {
				usage(options);
				return;
			}
		} catch (Exception e) {
		}

		try {
			commandLine = parser.parse(options, args);
			fileName = commandLine.getOptionValue(UrlInspect.EXCEL);

			String argValue = commandLine.getOptionValue(UrlInspect.FROM);
			if (argValue != null) {
				try {
					from = Integer.parseInt(argValue);
				} catch (NumberFormatException e) {
					throw new Exception("value of `" + UrlInspect.FROM + "` is invalid!");
				}
			}

			argValue = commandLine.getOptionValue(UrlInspect.TO);
			if (argValue != null) {
				try {
					to = Integer.parseInt(argValue);
				} catch (NumberFormatException e) {
					throw new Exception("value of `" + UrlInspect.TO + "` is invalid!");
				}
			}

			argValue = commandLine.getOptionValue(UrlInspect.THREADS);
			if (argValue != null) {
				try {
					threads = Integer.parseInt(argValue);
				} catch (NumberFormatException e) {
					throw new Exception("value of `" + UrlInspect.THREADS + "` is invalid!");
				}
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
			usage(options);
			return;
		}

		File file = new File(fileName);
		if (!file.exists()) {
			System.out.println("`" + fileName + "` not exists!");
			return;
		}

		if (!file.isFile()) {
			System.out.println("`" + fileName + "` is not a regular file!");
			return;
		}

		ArrayList<TreeMap<String, String>> arrayList = UrlInspect.ReadExcel(fileName);
		if (arrayList == null) {
			return;
		}

		// now `from` is 0 based
		if (from > 0) {
			if (from > arrayList.size()) {
				from = arrayList.size() - 1;
			} else {
				from -= 1;
			}
		} else {
			from = 0;
		}

		// now `to` is 0 based, too
		if (to > 0) {
			if (to > arrayList.size()) {
				to = arrayList.size() - 1;
			} else {
				to -= 1;
			}
		} else {
			to = arrayList.size() - 1;
		}

		if (threads < 1) {
			threads = 10;
		}

		final int b = from;
		final int e = to;

		for (i = 0; i < threads; i++) {
			num++;
			new Thread(new Runnable() {
				@Override
				public void run() {
					while (true) {
						for (int j = b; j <= e; j++) {
							TreeMap<String, String> map = arrayList.get(j);
							switch (map.get(UrlInspect.METHOD)) {
							case "POST":
								HTTPUtil.post(map.get(UrlInspect.URL), map.get(UrlInspect.APIKEY),
										map.get(UrlInspect.PAYLOAD));
								break;

							case "DELETE":
								HTTPUtil.delete(map.get(UrlInspect.URL), map.get(UrlInspect.APIKEY));
								break;

							case "PUT":
								HTTPUtil.put(map.get(UrlInspect.URL), map.get(UrlInspect.APIKEY),
										map.get(UrlInspect.PAYLOAD));
								break;

							case "GET":
								HTTPUtil.get(map.get(UrlInspect.URL), map.get(UrlInspect.APIKEY));
								break;

							default:
								break;
							}
						}
					}
				}
			}).start();
		}

		long sec = 0;
		while (true) {
			Thread.sleep(5000);
			sec += 5;
			System.out.println(sec + " seconds elapsed");
		}
	}
}
